package com.controller;

import com.bean.*;
import com.service.IGoodsService;
import com.service.IOrderService;
import com.service.ISeckillService;
import com.service.IUserService;
import com.shiro.token.JWTToken;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 秒杀活动的controller
 *
 * @author WxrStart
 * @create 2022-05-20 9:04
 */
@Controller
@Slf4j
@RequestMapping("/seckill")
public class SeckillController {

    @Autowired
    private IOrderService iOrderService;
    @Autowired
    private ISeckillService iSeckillService;
    @Autowired
    private IGoodsService iGoodsService;
    @Autowired
    private IUserService iUserService;
    @Autowired
    StringRedisTemplate redisTemplate;

    /**
     * 访问秒杀活动页
     *
     * @return
     */
    @GetMapping("/gotoSeckillPage")
    @ResponseBody
    public Msg gotoSeckill() {
        log.info("访问到了秒杀活动页");
        return Msg.success().add("result", "登陆成功");
    }


    /**
     * 刷新秒杀活动页面
     *
     * @param goodsName
     * @return
     */
    @GetMapping("/getSeckillGoods/{goodsName}")
    @ResponseBody
    public Msg getSeckillGoods(@PathVariable String goodsName) {

        //获取秒杀活动对象
        Seckill seckill = iSeckillService.getSeckill(goodsName);
        if (seckill == null) {
            return Msg.fail().add("result", "该商品不是秒杀活动商品");
        }
        //获取秒杀活动开始和结束时间
        Date startTime = seckill.getStartTime();
        Date endTime = seckill.getEndTime();
        //获取商品对象
        Goods goods = iGoodsService.getGoodsByName(goodsName);
        //判断商品对象是否为空
        if (goods == null) {
            return Msg.fail().add("result", "暂无该商品");
        }
        //判断当前秒杀活动是否过期
        Date date = new Date();
        if (date.before(startTime)) {
            return Msg.fail().add("result", "秒杀活动还未开始");
        }
        if (date.after(endTime)) {
            return Msg.fail().add("result", "秒杀活动已结束");
        }

        if (goods.getIsSeckill() == 0) {
            return Msg.fail().add("result", "该商品不是秒杀活动商品");
        } else {
            return Msg.success().add("goods", goods).add("seckill", seckill);
        }
    }


    /**
     * 进行秒杀
     *
     * @param goodsName
     * @return
     */
    @GetMapping("/doSeckill/{goodsName}")
    @ResponseBody
    public Msg doSeckill(@PathVariable String goodsName, @RequestHeader("x-access-token") String jwt) {
        //把jwt转化为Token，因为已经走了jwt认证了不需要判空和校验
        JWTToken jwtToken = new JWTToken(jwt);
        //解析jwt查找到user对象
        String email = jwtToken.getEmail();
        User user = iUserService.findByEmail(email);
        //获取秒杀的商品
        Goods secgoods = iGoodsService.getGoodsByName(goodsName);
        //获取秒杀活动对象
        Seckill seckill = iSeckillService.getSeckill(goodsName);
        //获取秒杀商品的库存
        Integer stock = secgoods.getGoodsStock();
        if (stock == 0) {
            return Msg.fail().add("result", "商品已售空");
        }
        //判断用户是否重复参与秒杀活动(通过userId查找orderId，再通过orderId查找商品是否是当前商品)
        List<Orders> ordersSeckill = iOrderService.getOrders(user);
        if (ordersSeckill.size() != 0) {
            for (int i = 0; i < ordersSeckill.size(); i++) {
                Map omap = (Map) ordersSeckill.get(i);
                Object obJorderId =  omap.get("OrderId");
                String s = obJorderId.toString();
                Integer orderId = Integer.parseInt(s);
                Goods goodsByOrderId = iGoodsService.getGoodsByOrderId(orderId);
                String goodsName1 = goodsByOrderId.getGoodsName().trim();
                if (goodsName.equals(goodsName1)) {
                    return Msg.fail().add("result", "用户已参加过");
                }
            }
        }
            //开始秒杀
            //生成UUID
            String uuid = UUID.randomUUID().toString();
            //设置锁过期时间，防止死锁
            //相当于setnx
            Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", uuid, 60, TimeUnit.SECONDS);
            //获取锁成功
            if (lock) {
                //生成订单
                Orders orders = new Orders();

                orders.setOrderPrice(secgoods.getGoodsPrice());
                orders.setOrderStatus(1);
                orders.setOuId(user.getUserId());
                orders.setIsSeckillorder(1);
                iOrderService.createOrders(orders);
                //给中间表orders_goods插入数据
                iSeckillService.addorders_goods(orders.getOrderId(), secgoods.getGoodsId());
                //给中间表user_seckill插入数据
                iSeckillService.adduser_seckill(user.getUserId(), seckill.getSeckillId());
                //给中间表seckill_order
                //商品库存-1
                secgoods.setGoodsStock(--stock);
                //更新库存
                iGoodsService.updateGoods(secgoods);
                //使用LUA脚本执行原子操作，避免锁误删
                String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
                // 设置一下返回值类型 为Long
                DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
                redisScript.setScriptText(script);
                // 因为删除判断的时候，返回的0,给其封装为数据类型。如果不封装那么默认返回String 类型，
                // 那么返回字符串与0 会有发生错误。
                redisScript.setResultType(Long.class);
                // 第一个要是script 脚本 ，第二个需要判断的key，第三个就是key所对应的值。
                redisTemplate.execute(redisScript, Arrays.asList("lock"), uuid);
                return Msg.success().add("result", "秒杀成功").add("goods", secgoods).add("userEmail", email);
            } else {
                return Msg.fail().add("result", "秒杀失败");
            }


    }


    /**
     * 查看秒杀商品的库存和时间
     *
     * @param
     * @return
     */
    @GetMapping("/getSeckillStock/{goodsName}")
    @ResponseBody
    public Msg getStock(@PathVariable String goodsName) {
        Integer goodsStock = iGoodsService.getGoodsByName(goodsName).getGoodsStock();
        Date endTime = iSeckillService.getSeckill(goodsName).getEndTime();

        return Msg.success().add("stock", goodsStock).add("endTime", endTime);
    }


    /**
     * 查找商品是否为秒杀商品
     *
     * @return
     */
    @GetMapping("/getGoodsByIsSeckill")
    @ResponseBody
    public Msg getGoodsByIsSeckill() {
        Goods goodsByIs_seckill = iGoodsService.getGoodsByIs_Seckill();
        if (goodsByIs_seckill != null) {
            return Msg.success().add("result", goodsByIs_seckill);
        } else {
            return Msg.fail().add("result", "暂无该商品");
        }
    }

    /**
     * 查找秒杀订单
     *
     * @return
     */
    @GetMapping("/getSecOrdersByUser")
    @ResponseBody
    public Msg getSecOrdersByUser(@RequestHeader("x-access-token") String jwt) {
        //把jwt转化为Token，因为已经走了jwt认证了不需要判空和校验
        JWTToken jwtToken = new JWTToken(jwt);
        //解析jwt查找到user对象
        String email = jwtToken.getEmail();
        User user = iUserService.findByEmail(email);
        //查找订单
        List<Orders> orders = iOrderService.getOrders(user);
        if (orders.size() != 0) {
            return Msg.success().add("user", email).add("orders", orders);
        } else {
            return Msg.fail().add("result", "暂无秒杀订单").add("user", email);
        }
    }


}

